通过脚手架命令Command类封装
2. 利用Node多进程动态执行命令(stdio的inherit属性讲解)
我们回到exec/lib/index.js中,其中之前的那行代码 require(rootFile).call(null,Array.from(arguments)); 是在当前进程中调用的,我们需要修改为在node进程中进行调用,这便是本节的重点。
我们通过本周第五章的内容,已经知道了如何使用child_process下的同步或者异步方法进行子进程的执行,这里我有两种方法可以使用
const cp = require('child_process')
// cp.fork() //这里因为fork没有回调,需要通过通信的方式来获取结果,所以这里不推荐
//之所以不用spawnSync是因为,我们在执行这里的时候是需要不断的用户交互的,需要不断的收到数据打印结果,不要一次性
const child = cp.spawn('node',['-e',code],{
cwd:process.cwd(),
stdio:'inherit' // 加入这行代码,下面的就可以注释掉了
})
// child.stdout.on('data',(chunk =>{
// }))
// child.stderr.on('data',(chunk =>{
// }))
// 当然存在错误的情况,我们还是需要添加两个监听事件
child.on('error', e =>{
log.error(e.message);
process.exit(1);
})
child.on('exit', e=>{
log.verbose('命令执行成功' + e);
process.exit(e);
})
spawn方法中的参数stdio默认值为'pipe'管道,pipe使得主进程与子进程会产生通信通道,因此需要通过on这种方式去进行监听。 stdio还有一个值为'inherit',它将相应的stdio传给父进程或者从父进程传入。也就是说:直接将process.stdin、process.stdout、process.stderr直接和父进程进行绑定,这样就无须去监听结果,可以直接将结果打印出来。
3. 生成Node多进程动态执行代码
通过上一节的学习,我们通过代码const args = Array.from(arguments) const cmd = args[args.length - 1]可以知道,现在需要做的就是拼成上面spawn在执行时所需的code 我们之前的代码为 _require(rootFile).call(null,Array.from(arguments)); 也就是兼容 conse code = require(rootFile).call(null,Array.from(arguments)); rootfile -> ${rootfile},难点是 Array.from(arguments)的传入。
onst args = Array.from(arguments)
const cmd = args[args.length - 1] // 拿到command,且进行瘦身,对不需要的参数进行过滤
const o = Object.create(null)
Object.keys(cmd).forEach(key=>{
if(cmd.hasOwnProperty(key) && !key.startsWith('_')&& key!=='parent'){
o[key]=cmd[key]
}
})
args[args.length-1] = o
const code = `require('${rootFile}').call(null,${JSON.stringify(args)})`
注:由于我使用的commander是7.0.0的,低于此版本传入的参数为两个,但7.0.0版本传入参数为3个,因此上面的代码,我这里直接写成(不知道后续是否还会有错误):
let args = Array.from(arguments).splice(0,2)
const code = `require('${rootFile}').call(null,${JSON.stringify(args)})`
到这里,使用node多进程执行代码的功能就完成了。
4. windows操作系统spawn执行命令兼容
windows操作系统与macOS关于spawn的执行是不一样的,本节解决的就是windows操作系统下的兼容 将本方法封装在utils/utils包中:通过process.platform来判断操作系统
function exec(command,args,options){
const win32 = process.platform === 'win32';
const cmd = win32 ? 'cmd': command
const cmdArgs = win32 ? ['/c'].concat(command,args) : args;
return require('child_process').spawn(cmd, cmdArgs,options || {})
}
到以上为止,我们完成了动态命令的加载和执行。
若有收获,就点个赞吧